﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.WebControls;
using SmartParking.Data;
using SmartParking.Data.Entities;

namespace SmartParking.Bussiness
{
    public class ParkingManager
    {
        #region Customers

        private const string CustomerTableName = "Customers";

        /// <summary>
        /// Return all customers
        /// </summary>
        public static List<Customer> GetCustomers()
        {
            using (var context = new SmartParkingContext())
            {
                return context.Customers.Where(item => !item.Deleted).ToList();
            }
        }

        /// <summary>
        /// Get customer by id
        /// </summary>
        public static Customer GetCustomer(int id, SmartParkingContext context = null)
        {
            var innerContext = context ?? new SmartParkingContext();
            try
            {
                return innerContext.Customers.SingleOrDefault(item => item.CustomerID == id && !item.Deleted);
            }
            finally
            {
                if (context == null) innerContext.Dispose();
            }
        }

        /// <summary>
        /// Bind all customers into a drop down list
        /// </summary>
        public static void BindCustomers(ref DropDownList list)
        {
            list.DataSource = GetCustomers();
            list.DataTextField = "Name";
            list.DataValueField = "CustomerID";
            list.DataBind();
        }

        /// <summary>
        /// Bind all customers into a grid view
        /// </summary>
        public static void BindCustomers(ref ADEVSO.Web.UI.WebControls.GridView grid)
        {
            grid.DataSource = GetCustomers();
            grid.DataBind();
        }

        /// <summary>
        /// Add new customer
        /// </summary>
        private static void AddCustomer(string name, string email, string phone, string address, int managerId, string ipAddress)
        {
            using (var context = new SmartParkingContext())
            {
                var row = new Customer
                    {
                        Name = name,
                        Email = email,
                        Phone = phone,
                        Address = address
                    };
                context.Customers.Add(row);
                context.SaveChanges();
                LogManager.Log(managerId, LogActions.INSERT, ipAddress, CustomerTableName, row.CustomerID.ToString());
            }
        }

        /// <summary>
        /// Update a customer
        /// </summary>
        private static void UpdateCustomer(int customerId, string name, string email, string phone, string address, int managerId, string ipAddress)
        {
            using (var context = new SmartParkingContext())
            {
                var row = GetCustomer(customerId, context);
                row.Name = name;
                row.Email = email;
                row.Phone = phone;
                row.Address = address;
                context.SaveChanges();
                LogManager.Log(managerId, LogActions.UPDATE, ipAddress, CustomerTableName, row.CustomerID.ToString());
            }
        }

        /// <summary>
        /// Save a customer
        /// </summary>
        public static void SaveCustomer(string customerId, string name, string email, string phone, string address, int managerId, string ipAddress)
        {
            if (String.IsNullOrEmpty(customerId))
                ParkingManager.AddCustomer(name, email, phone, address, managerId, ipAddress);
            else
                ParkingManager.UpdateCustomer(Convert.ToInt32(customerId), name, email, phone, address, managerId, ipAddress);
        }

        /// <summary>
        /// Delete a customer
        /// </summary>
        public static void DeleteCustomer(int customerId, int managerId, string ipAddress)
        {
            using (var context = new SmartParkingContext())
            {
                var row = ParkingManager.GetCustomer(customerId, context);
                row.Deleted = true;
                //context.Customers.Attach(row);
                //context.ObjectStateManager.ChangeObjectState(row, EntityState.Modified);
                context.SaveChanges();
                LogManager.Log(managerId, LogActions.DELETE, ipAddress, CustomerTableName, row.CustomerID.ToString());
            }
        }

        #endregion

        #region Parkings

        private const string ParkingsTableName = "Parkings";

        /// <summary>
        /// Return all parkings
        /// </summary>
        public static List<Parking> GetParkings(Func<Parking, bool> conditions = null)
        {
            using (var context = new SmartParkingContext())
            {
                if (conditions == null) conditions = item => !item.Deleted;
                else conditions += item => !item.Deleted;
                return context.Parkings.Where(conditions).ToList();
            }
        }

        /// <summary>
        /// Return all parkings allowing web reservations
        /// </summary>
        public static List<Parking> GetParkingsToWebReservations()
        {
            return GetParkings(item => GetParkingZonesToWebReservations(item.ParkingID).Any());
        }

        /// <summary>
        /// Return all parkings of a customer
        /// </summary>
        public static List<Parking> GetParkings(int customerId)
        {
            return GetParkings(item => item.CustomerID == customerId);
        }

        /// <summary>
        /// Get parking by id
        /// </summary>
        public static Parking GetParking(int id, SmartParkingContext context = null)
        {
            var innerContext = context ?? new SmartParkingContext();
            try
            {
                return innerContext.Parkings.SingleOrDefault(item => item.ParkingID == id);
            }
            finally
            {
                if (context == null) innerContext.Dispose();
            }
        }

        /// <summary>
        /// Bind all parking into a drop down list
        /// </summary>
        public static void BindParkings(ref DropDownList list)
        {
            list.DataSource = GetParkingsToWebReservations();
            list.DataTextField = "Name";
            list.DataValueField = "ParkingID";
            list.DataBind();
        }

        /// <summary>
        /// Bind all parking of a customer into a drop down list
        /// </summary>
        public static void BindParkings(ref DropDownList list, int customerId)
        {
            list.DataSource = GetParkings(customerId);
            list.DataTextField = "Name";
            list.DataValueField = "ParkingID";
            list.DataBind();
        }

        /// <summary>
        /// Bind all parking of a customer into a grid
        /// </summary>
        public static void BindParkings(ref ADEVSO.Web.UI.WebControls.GridView grid, int customerId)
        {
            grid.DataSource = GetParkings(customerId);
            grid.DataBind();
        }

        /// <summary>
        /// Add new parking
        /// </summary>
        private static void AddParking(int customerId, string name, string legalId, string legalName, string bankAccountNumber, string address, string phone, int managerId, string ipAddress)
        {
            using (var context = new SmartParkingContext())
            {
                var row = new Parking
                    {
                        CustomerID = customerId,
                        Name = name,
                        LegalID = legalId,
                        LegalName = legalName,
                        BankAccountNumber = bankAccountNumber,
                        Address = address,
                        Phone = phone
                    };
                context.Parkings.Add(row);
                context.SaveChanges();
                LogManager.Log(managerId, LogActions.INSERT, ipAddress, ParkingsTableName, row.ParkingID.ToString());
            }
        }

        /// <summary>
        /// Update a parking
        /// </summary>
        private static void UpdateParking(int parkingId, string name, string legalId, string legalName, string bankAccountNumber, string address, string phone, int managerId, string ipAddress)
        {
            using (var context = new SmartParkingContext())
            {
                var row = GetParking(parkingId, context);
                row.Name = name;
                row.LegalID = legalId;
                row.LegalName = legalName;
                row.BankAccountNumber = bankAccountNumber;
                row.Address = address;
                row.Phone = phone;
                context.SaveChanges();
                LogManager.Log(managerId, LogActions.UPDATE, ipAddress, ParkingsTableName, row.ParkingID.ToString());
            }
        }

        /// <summary>
        /// Save a parking
        /// </summary>
        public static void SaveParking(int customerId, string parkingId, string name, string legalId, string legalName, string bankAccountNumber, string address, string phone, int managerId, string ipAddress)
        {
            if (String.IsNullOrEmpty(parkingId))
                AddParking(customerId, name, legalId, legalName, bankAccountNumber, address, phone, managerId, ipAddress);
            else
                UpdateParking(Convert.ToInt32(parkingId), name, legalId, legalName, bankAccountNumber, address, phone, managerId, ipAddress);
        }

        /// <summary>
        /// Delete a parking
        /// </summary>
        public static void DeleteParking(int parkingId, int managerId, string ipAddress)
        {
            using (var context = new SmartParkingContext())
            {
                var row = GetParking(parkingId, context);
                row.Deleted = true;
                context.SaveChanges();
                LogManager.Log(managerId, LogActions.DELETE, ipAddress, ParkingsTableName, row.ParkingID.ToString());
            }
        }

        #endregion

        #region Parking Zones

        private const string ParkingZonesTableName = "ParkingZones";

        /// <summary>
        /// Return all parking zones
        /// </summary>
        public static List<ParkingZone> GetParkingZones(Func<ParkingZone, bool> conditions)
        {
            using (var context = new SmartParkingContext())
            {
                if (conditions == null) conditions = item => !item.Deleted && !item.Parking.Deleted;
                else conditions += item => !item.Deleted && !item.Parking.Deleted;
                return context.ParkingZones.Where(conditions).ToList();
            }
        }

        /// <summary>
        /// Return all parking zones of a parking
        /// </summary>
        public static List<ParkingZone> GetParkingZones(int parkingId)
        {
            return GetParkingZones(item => item.ParkingID == parkingId);
        }

        /// <summary>
        /// Return all parking zones allowing web reservations
        /// </summary>
        public static List<ParkingZone> GetParkingZonesToWebReservations(Func<ParkingZone, bool> conditions = null)
        {
            if (conditions == null) conditions = item => item.ParkingZoneFares.Any(item2 => item2.Name.ToUpper().Trim().Equals("WEB"));
            else conditions += item => item.ParkingZoneFares.Any(item2 => item2.Name.ToUpper().Trim().Equals("WEB"));
            return GetParkingZones(conditions);
        }

        /// <summary>
        /// Return all parking zones of a parking allowing web reservations
        /// </summary>
        public static List<ParkingZone> GetParkingZonesToWebReservations(int parkingId, Func<ParkingZone, bool> conditions = null)
        {
            if (conditions == null) conditions = item => item.ParkingID == parkingId;
            else conditions += item => item.ParkingID == parkingId;
            return GetParkingZonesToWebReservations(conditions);
        }

        /// <summary>
        /// Return parking zone by id
        /// </summary>
        public static ParkingZone GetParkingZone(int parkingZoneId, SmartParkingContext context = null)
        {
            var innerContext = context ?? new SmartParkingContext();
            try
            {
                return innerContext.ParkingZones.SingleOrDefault(item => item.ParkingZoneID == parkingZoneId && !item.Deleted);
            }
            finally
            {
                if (context == null) innerContext.Dispose();
            }
        }

        /// <summary>
        /// Bind all parking zones of a parking into a drop down list
        /// </summary>
        public static void BindParkingZones(ref DropDownList list, int parkingId)
        {
            list.DataSource = ParkingManager.GetParkingZones(parkingId);
            list.DataTextField = "Name";
            list.DataValueField = "ParkingZoneID";
            list.DataBind();
        }

        /// <summary>
        /// Bind all parking zones of a parking into a grid
        /// </summary>
        public static void BindParkingZones(ref ADEVSO.Web.UI.WebControls.GridView grid, int parkingId)
        {
            grid.DataSource = GetParkingZones(parkingId);
            grid.DataBind();
        }

        /// <summary>
        /// Add new parking zone
        /// </summary>
        private static void AddParkingZone(int parkingId, string name, decimal managerCommisionAmount, decimal webCommisionAmount, bool allowHalfHour, string openHour, string closeHour, int regularSpaces, int spacesToReserve, int managerId, string ipAddress)
        {
            using (var context = new SmartParkingContext())
            {
                var row = new ParkingZone
                {
                    ParkingID = parkingId,
                    Name = name,
                    ManagerCommisionAmount = managerCommisionAmount,
                    WebCommisionAmount = webCommisionAmount,
                    AllowHalfHour = allowHalfHour,
                    OpenHour = openHour,
                    CloseHour = closeHour,
                    RegularSpaces = regularSpaces,
                    SpacesToReserve = spacesToReserve
                };
                context.ParkingZones.Add(row);
                context.SaveChanges();
                LogManager.Log(managerId, LogActions.INSERT, ipAddress, ParkingZonesTableName, row.ParkingZoneID.ToString());
            }
        }

        /// <summary>
        /// Update a parking zone
        /// </summary>
        private static void UpdateParkingZone(int parkingZoneId, string name, decimal managerCommisionAmount, decimal webCommisionAmount, bool allowHalfHour, string openHour, string closeHour, int regularSpaces, int spacesToReserve, int managerId, string ipAddress)
        {
            using (var context = new SmartParkingContext())
            {
                var row = GetParkingZone(parkingZoneId, context);
                row.Name = name;
                row.ManagerCommisionAmount = managerCommisionAmount;
                row.WebCommisionAmount = webCommisionAmount;
                row.AllowHalfHour = allowHalfHour;
                row.OpenHour = openHour;
                row.CloseHour = closeHour;
                row.RegularSpaces = regularSpaces;
                row.SpacesToReserve = spacesToReserve;
                context.SaveChanges();
                LogManager.Log(managerId, LogActions.UPDATE, ipAddress, ParkingZonesTableName, row.ParkingZoneID.ToString());
            }
        }

        /// <summary>
        /// Save a parking zone
        /// </summary>
        public static void SaveParkingZone(int parkingId, string parkingZoneId, string name, decimal managerCommisionAmount, decimal webCommisionAmount, bool allowHalfHour, string openHour, string closeHour, int regularSpaces, int spacesToReserve, int managerId, string ipAddress)
        {
            if (String.IsNullOrEmpty(parkingZoneId))
                AddParkingZone(parkingId, name, managerCommisionAmount, webCommisionAmount, allowHalfHour, openHour, closeHour, regularSpaces, spacesToReserve, managerId, ipAddress);
            else
                UpdateParkingZone(Convert.ToInt32(parkingZoneId), name, managerCommisionAmount, webCommisionAmount, allowHalfHour, openHour, closeHour, regularSpaces, spacesToReserve, managerId, ipAddress);
        }

        /// <summary>
        /// Delete a parking zone
        /// </summary>
        public static void DeleteParkingZone(int parkingZoneId, int managerId, string ipAddress)
        {
            using (var context = new SmartParkingContext())
            {
                var row = GetParkingZone(parkingZoneId, context);
                row.Deleted = true;
                context.SaveChanges();
                LogManager.Log(managerId, LogActions.DELETE, ipAddress, ParkingZonesTableName, row.ParkingZoneID.ToString());
            }
        }

        #endregion

        #region Parking Zones Fares

        private const string ParkingZoneFaresTableName = "ParkingZoneFares";

        /// <summary>
        /// Return all parking zone fares
        /// </summary>
        public static List<ParkingZoneFare> GetParkingZoneFares(Func<ParkingZoneFare, bool> conditions, bool includeParkingZoneInfo = false)
        {
            using (var context = new SmartParkingContext())
            {
                if (conditions == null) conditions = item => !item.Deleted;
                else conditions += item => !item.Deleted;
                return includeParkingZoneInfo ? context.ParkingZoneFares.Include("ParkingZone").Where(conditions).ToList() : context.ParkingZoneFares.Where(conditions).ToList();
            }
        }

        /// <summary>
        /// Return all parking zone fares
        /// </summary>
        public static List<ParkingZoneFare> GetParkingZoneFares(int parkingZoneId)
        {
            return GetParkingZoneFares(item => item.ParkingZoneID == parkingZoneId);
        }

        /// <summary>
        /// Return parking zone fare
        /// </summary>
        public static ParkingZoneFare GetParkingZoneFare(int parkingZoneFareId, SmartParkingContext context = null)
        {
            var innerContext = context ?? new SmartParkingContext();
            try
            {
                return innerContext.ParkingZoneFares.SingleOrDefault(item => item.ParkingZoneFareID == parkingZoneFareId && !item.Deleted);
            }
            finally
            {
                if (context == null) innerContext.Dispose();
            }
        }

        /// <summary>
        /// Return all parking zone web fares
        /// </summary>
        public static List<ParkingZoneFare> GetParkingZoneWebFares(Func<ParkingZoneFare, bool> conditions, bool includeParkingZoneInfo = false)
        {
            if (conditions == null) conditions = item => item.Name.ToUpper().Trim().Equals("WEB");
            else conditions += item => item.Name.ToUpper().Trim().Equals("WEB");
            return GetParkingZoneFares(conditions, includeParkingZoneInfo);
        }

        /// <summary>
        /// Return parking zone web fare
        /// </summary>
        public static ParkingZoneFare GetParkingZoneWebFare(int parkingZoneId)
        {
            var parkingZoneWebFares = GetParkingZoneWebFares(item => item.ParkingZoneID == parkingZoneId, true);
            if (parkingZoneWebFares.Any())
                return parkingZoneWebFares[0];
            return null;
        }

        /// <summary>
        /// Bind all parking zone fares into a drop down list
        /// </summary>
        public static void BindParkingZoneFares(ref DropDownList list, int parkingZoneId)
        {
            list.DataSource = GetParkingZoneFares(parkingZoneId);
            list.DataTextField = "Name";
            list.DataValueField = "ParkingZoneFareID";
            list.DataBind();
        }

        /// <summary>
        /// Add new parking zone fare
        /// </summary>
        private static void AddParkingZoneFare(int parkingId, int parkingZoneId, string name, decimal priceHour, int managerId, string ipAddress)
        {
            using (var context = new SmartParkingContext())
            {
                var row = new ParkingZoneFare
                {
                    ParkingID = parkingId,
                    ParkingZoneID = parkingZoneId,
                    Name = name,
                    PriceHour = priceHour
                };
                context.ParkingZoneFares.Add(row);
                context.SaveChanges();
                LogManager.Log(managerId, LogActions.INSERT, ParkingZoneFaresTableName, ipAddress, row.ParkingZoneFareID.ToString());
            }
        }

        /// <summary>
        /// Update a parking zone fare
        /// </summary>
        private static void UpdateParkingZoneFare(int parkingZoneFareId, string name, decimal priceHour, int managerId, string ipAddress)
        {
            using (var context = new SmartParkingContext())
            {
                var row = GetParkingZoneFare(parkingZoneFareId, context);
                row.Name = name;
                row.PriceHour = priceHour;
                context.SaveChanges();
                LogManager.Log(managerId, LogActions.UPDATE, ipAddress, ParkingZoneFaresTableName, row.ParkingZoneFareID.ToString());
            }
        }

        /// <summary>
        /// Save a parking zone fare
        /// </summary>
        public static void SaveParkingZoneFare(int parkingId, int parkingZoneId, string parkingZoneFareId, string name, decimal priceHour, int managerId, string ipAddress)
        {
            if (String.IsNullOrEmpty(parkingZoneFareId))
                AddParkingZoneFare(parkingId, parkingZoneId, name, priceHour, managerId, ipAddress);
            else
                UpdateParkingZoneFare(Convert.ToInt32(parkingZoneId), name, priceHour, managerId, ipAddress);
        }

        /// <summary>
        /// Delete a parking zone fare
        /// </summary>
        public static void DeleteParkingZoneFare(int parkingZoneFareId, int managerId, string ipAddress)
        {
            using (var context = new SmartParkingContext())
            {
                var row = GetParkingZoneFare(parkingZoneFareId, context);
                row.Deleted = true;
                context.SaveChanges();
                LogManager.Log(managerId, LogActions.DELETE, ipAddress, ParkingZoneFaresTableName, row.ParkingZoneFareID.ToString());
            }
        }

        #endregion
    }
}